/**
 * @file	pwm.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/*******************************************************************************
* @file		pwm.c
* @brief	Contains all functions support for pwm driver
* @version	0.0
* @date		30. Oct. 2017
* @author	Ding
* 

*
*******************************************************************************/
#include "sdk_config.h"
#include "rom_sym_def.h"
#include "gpio.h"
#include "clock.h"
#include "pwm.h"
#include "pwrmgr.h"

/**************************************************************************************
 * @fn          HalPwmInit
 *
 * @brief       This function process for pwm initial
 *
 * input parameters
 *
 * @param       PwmCh_t pwmN						: pwm channel
 *              PwmClkDiv_t pwmDiv			: clock prescaler of PWM channel
 *				PwmMode_t pwmMode			: count mode of PWM channel
 *				PwmPolarity_t pwmPolarity		: output polarity setting of PWM channel
 *				unsigned short cmpVal			: the compare value of PWM channel 
 *				unsigned short cntTopVal		: the counter top value of PWM channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void HalPwmInit(
					PwmCh_t pwmN,
					PwmClkDiv_t pwmDiv,
					PwmMode_t pwmMode,
					PwmPolarity_t pwmPolarity)
{
    hal_clk_gate_enable(MOD_PWM);
    PWM_DISABLE_CH(pwmN);

    PWM_SET_DIV(pwmN, pwmDiv);
    PWM_SET_MODE(pwmN, pwmMode);
    PWM_SET_POL(pwmN, pwmPolarity);

    PWM_INSTANT_LOAD_CH(pwmN);
    hal_pwrmgr_register(MOD_PWM, NULL, NULL);
}

static GpioPin_t pwm_gpio_map[]={
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
};
/**************************************************************************************
 * @fn          HalPwmOpenChannel
 *
 * @brief       This function process for pwm start working
 *
 * input parameters
 *
 * @param       PwmCh_t pwmN						: pwm channel
 *              GpioPin_t pwmPin				: pwm pin number
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void HalPwmOpenChannel(PwmCh_t pwmN,GpioPin_t pwmPin)
{
    HalGpioFmuxConfig(pwmPin, (gpio_fmux_e)(FMUX_PWM0 + pwmN));
    PWM_ENABLE_CH(pwmN);
    pwm_gpio_map[pwmN] = pwmPin;
}

/**************************************************************************************
 * @fn          HalPwmCloseChannel
 *
 * @brief       This function process for pwm stop working
 *
 * input parameters
 *
 * @param       PwmCh_t pwmN						: pwm channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void HalPwmCloseChannel(PwmCh_t pwmN)
{	
	if(pwm_gpio_map[pwmN] != GPIO_DUMMY)
    {
		HalGpioFmuxEnable(pwm_gpio_map[pwmN],Bit_DISABLE); 
		pwm_gpio_map[pwmN] = GPIO_DUMMY;
	}
	PWM_DISABLE_CH(pwmN);
}

/**************************************************************************************
 * @fn          HalPwmDestroy
 *
 * @brief       This function process for pwm clear and disable
 *
 * input parameters
 *
 * @param       PwmCh_t pwmN						: pwm channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void HalPwmDestroy(PwmCh_t pwmN)
{
    PWM_DISABLE_CH(pwmN);
    PWM_NO_LOAD_CH(pwmN);
    PWM_NO_INSTANT_LOAD_CH(pwmN);
	
    PWM_SET_DIV(pwmN, 0);
    PWM_SET_MODE(pwmN, 0);
    PWM_SET_POL(pwmN, 0);
		
    PWM_SET_TOP_VAL(pwmN, 0);
    PWM_SET_CMP_VAL(pwmN, 0);
}

/**************************************************************************************
 * @fn          HalPwmSetCountVal
 *
 * @brief       This function process for change pwm count value
 *
 * input parameters
 *
 * @param       PwmCh_t pwmN						: pwm channel
 *				uint16_t cmpVal					: the compare value of PWM channel 
 *				uint16_t cntTopVal				: the counter top value of PWM channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void HalPwmSetCountVal(PwmCh_t pwmN, uint16_t cmpVal, uint16_t cntTopVal)
{
	if(cmpVal > cntTopVal)
		return;	
	PWM_NO_LOAD_CH(pwmN);
	PWM_SET_CMP_VAL(pwmN, cmpVal);
	PWM_SET_TOP_VAL(pwmN, cntTopVal);
	PWM_LOAD_CH(pwmN);
}

static unsigned int pwm_en = 0;
void HalPwmStart(void)
{
	if(pwm_en == 0)
	{
		hal_pwrmgr_lock(MOD_PWM);
		PWM_ENABLE_ALL;
		pwm_en = 1;
	}
}

void HalPwmStop(void)
{
	if(pwm_en == 1)
	{
		hal_pwrmgr_unlock(MOD_PWM);
		PWM_DISABLE_ALL;
		pwm_en = 0;
		hal_clk_gate_disable(MOD_PWM);
	}
}

//------------------------------------------------------------
//new api,make use easily
typedef struct {
    bool          enable;
    bool          ch_en[6];
    PwmCfg_t      ch[6];
}pwm_Ctx_t;

static pwm_Ctx_t pwmCtx = 
{
	.enable = FALSE,
	.ch_en = {FALSE,FALSE,FALSE,FALSE,FALSE,FALSE},
};

void HalPwmModuleInit(void)
{
	int i = 0;
		
	if(pwmCtx.enable == TRUE)
		return;
	pwmCtx.enable = TRUE;
	
	for(i = 0;i < 6;i++)
	{
		pwmCtx.ch_en[i] = FALSE;
		
		pwmCtx.ch[i].pwmN = (PwmCh_t)i;		
		pwmCtx.ch[i].pwmPin = GPIO_DUMMY;		
		pwmCtx.ch[i].pwmDiv = PWM_CLK_NO_DIV;
		pwmCtx.ch[i].pwmMode = PWM_CNT_UP;
		pwmCtx.ch[i].pwmPolarity = PWM_POLARITY_RISING;
		pwmCtx.ch[i].cmpVal = 0;
		pwmCtx.ch[i].cntTopVal = 0;
		
		HalPwmDestroy((PwmCh_t)i);	
	}		
	
	HalPwmStop();
}

void HalPwmModuleDeinit(void)
{
	int i = 0;
		
	if(pwmCtx.enable == FALSE)
		return;
	pwmCtx.enable = FALSE;
	
	for(i = 0;i < 6;i++)
	{
		pwmCtx.ch_en[i] = FALSE;
		
		pwmCtx.ch[i].pwmN = (PwmCh_t)i;		
		pwmCtx.ch[i].pwmPin = GPIO_DUMMY;		
		pwmCtx.ch[i].pwmDiv = PWM_CLK_NO_DIV;
		pwmCtx.ch[i].pwmMode = PWM_CNT_UP;
		pwmCtx.ch[i].pwmPolarity = PWM_POLARITY_RISING;
		pwmCtx.ch[i].cmpVal = 0;
		pwmCtx.ch[i].cntTopVal = 0;
		
		HalPwmCloseChannel((PwmCh_t)i);
		HalPwmDestroy((PwmCh_t)i);	
	}	
	
	HalPwmStop();
}

void HalPwmChannelStart(PwmCfg_t ch)
{
	if(pwmCtx.enable == FALSE)
		return;
	
	if(pwmCtx.ch_en[ch.pwmN] == TRUE)
	{
		HalPwmSetCountVal(ch.pwmN,ch.cmpVal,ch.cntTopVal);
		PWM_SET_DIV(ch.pwmN, ch.pwmDiv);
	}
	else
	{
		HalPwmInit(ch.pwmN,ch.pwmDiv,ch.pwmMode,ch.pwmPolarity);
		HalPwmSetCountVal(ch.pwmN,ch.cmpVal,ch.cntTopVal);
		HalPwmOpenChannel(ch.pwmN,ch.pwmPin);
		pwmCtx.ch_en[ch.pwmN] = TRUE;

		HalPwmStart();
	}
}

void HalPwmChannelStop(PwmCh_t pwmN)
{
	if(pwmCtx.ch_en[pwmN] == FALSE)
		return;
	else
	{
		pwmCtx.ch_en[pwmN] = FALSE;		
		HalPwmDestroy(pwmN);	
		HalPwmCloseChannel(pwmN);		
	}	
}

bool HalPwmChannelEnable(PwmCh_t pwmN)
{
	return pwmCtx.ch_en[pwmN];
}

PwmCfg_t HalPwmChannelReg(PwmCh_t pwmN)
{
	return pwmCtx.ch[pwmN];
}
